#include <bsp/malloc.h>
#include <cpp/crt.h>
#include <cstddef>
#include <exception>
#include <new>
#include <units.h>

extern bool isSchedulerStart;

/* --- 重载new delete ---- */
[[nodiscard]] void* operator new(std::size_t size) noexcept(false) {
  if (size == 0) size = 1;

  if (isSchedulerStart) {
    if (void* p = os_malloc(size))
      return p;
  }

  while (true) {
    if (void* p = malloc(size))
      return p;

    std::new_handler handler = std::get_new_handler();
    if (!handler) {
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
      throw std::bad_alloc();
#else
      std::abort();
#endif
    }
    handler();
  }
}

[[nodiscard]] void* operator new[](std::size_t size) noexcept(false) {
  if (size == 0) size = 1;

  if (isSchedulerStart) {
    if (void* p = os_malloc(size))
      return p;
  }

  while (true) {
    if (void* p = std::malloc(size))
      return p;

    std::new_handler handler = std::get_new_handler();
    if (!handler) {
#if defined(__cpp_exceptions) || defined(__EXCEPTIONS)
      throw std::bad_alloc();
#else
      std::abort();
#endif
    }
    handler();
  }
}

void operator delete(void* ptr) noexcept {
  if (isSchedulerStart) os_free(ptr);
  else std::free(ptr);
}

void operator delete(void* ptr, std::size_t size) noexcept {
  (void)size;
  if (isSchedulerStart) os_free(ptr);
  else std::free(ptr);
}

void operator delete[](void* ptr, std::size_t size) noexcept {
  (void)size;
  os_free(ptr);
}

void operator delete[](void* ptr) noexcept { os_free(ptr); }

void __cxa_pure_virtual(void) {
  while (true) {
    // TODO: __cxa_pure_virtual
  }
}

[[noreturn]] void Terminate() noexcept {
  while (true) {
  }
}

#ifdef __clang__
/* ---- 保留armlib提供的全局对象构造 ---- */
extern "C" void $Super$$__cpp_initialize__aeabi_(void);

bool is_CXX_GlobalInit = false;

/* ---- 劫持armlib的全局对象构造并重定向到本函数 ---- */
extern "C" void $Sub$$__cpp_initialize__aeabi_(void) {
  if (is_CXX_GlobalInit) $Super$$__cpp_initialize__aeabi_();
}

/* ---- 构造全局对象 ---- */
int CXX_GlobalInit() {
  is_CXX_GlobalInit = true;

  $Super$$__cpp_initialize__aeabi_();

  is_CXX_GlobalInit = false;

  return 0;
}
#else
/* ---- 读表构造全局对象 ---- */
extern "C" {
  typedef void (*pfunc)();
  extern pfunc __init_array_start[];
  extern pfunc __init_array_end[];
  int CXX_GlobalInit(void) {
    for (pfunc* p = __init_array_start; p < __init_array_end; p++) {
      (*p)();
    }

    return 0;
  }
}
#endif